/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package yoga.algo.phenotype;

import java.util.HashMap;
import java.util.Iterator;
import yoga.algo.coding.ICoding;

/**
 *
 * @author Yogev Montekyo
 */
public class PopulationStatistics<T> implements Iterable<Individual<T>>
{
    private IFitnessCalculator<T> m_fitnessCalculator;
    private Population<T> m_population;
    private double NuetralOrZeroValue;
    private double MeanFitnessValue;
    private double MedianFitnessValue;
    private double MinFitnessValue;
    private double MaxFitnessValue;
    private double SumFitnessValue;
    private HashMap<Individual<T>, Double> m_hashMapIndividualsFitness;

    public PopulationStatistics(double Mean, double Median, double Min,
            double Max, double Sum, double Nuetral)
    {
        NuetralOrZeroValue = Nuetral;
        MeanFitnessValue = Mean;
        MedianFitnessValue = Median;
        MinFitnessValue = Min;
        MaxFitnessValue = Max;
        SumFitnessValue = Sum;
        m_population = null;
    }

    public PopulationStatistics(IFitnessCalculator<T> fitnessCalculator)
    {
        m_fitnessCalculator = fitnessCalculator;
        resetFitnessValues();
    }

    private void resetFitnessValues()
    {
        MeanFitnessValue = m_fitnessCalculator.getNeutralOrZeroValue();
        MedianFitnessValue = m_fitnessCalculator.getNeutralOrZeroValue();
        MinFitnessValue = m_fitnessCalculator.getMaximumValue();
        MaxFitnessValue = m_fitnessCalculator.getNeutralOrZeroValue();
        SumFitnessValue = m_fitnessCalculator.getNeutralOrZeroValue();
        NuetralOrZeroValue = m_fitnessCalculator.getNeutralOrZeroValue();
    }

    public double getFitnessValue(Individual<T> individual)
    {
        double fitnessValue = m_fitnessCalculator.getNeutralOrZeroValue();
        if (m_hashMapIndividualsFitness != null)
        {
            fitnessValue = m_hashMapIndividualsFitness.get(individual);
        }
        return fitnessValue;
    }

    public void updateStatistics(Population<T> population)
    {
        m_population = population;
        if (m_fitnessCalculator != null)
        {
            resetFitnessValues();
            m_hashMapIndividualsFitness = new HashMap<Individual<T>, Double>();
            for (Individual<T> individual : population)
            {

                if (!m_hashMapIndividualsFitness.containsKey(individual))
                {
                    double currentFitnessValue = m_fitnessCalculator.getFitnessValue(individual.getPhenotype());
                    m_hashMapIndividualsFitness.put(individual, currentFitnessValue);

                    if (MinFitnessValue > currentFitnessValue)
                    {
                        MinFitnessValue = currentFitnessValue;
                    }
                    if (currentFitnessValue > MaxFitnessValue)
                    {
                        MaxFitnessValue = currentFitnessValue;
                    }

                    SumFitnessValue += currentFitnessValue;
                }

            }
            

            MeanFitnessValue = SumFitnessValue / m_hashMapIndividualsFitness.size();
            MedianFitnessValue = (MinFitnessValue + MaxFitnessValue) / 2;
        }
    }

    public double getMeanFitnessValue()
    {
        return MeanFitnessValue;
    }

    public double getMedianFitnessValue()
    {
        return MedianFitnessValue;
    }

    public double getMinFitnessValue()
    {
        return MinFitnessValue;
    }

    public double getMaxFitnessValue()
    {
        return MaxFitnessValue;
    }

    public double getSumFitnessValue()
    {
        return SumFitnessValue;
    }

    public double getNuetralOrZeroValue()
    {
        return NuetralOrZeroValue;
    }

    public int size()
    {
        int size = 0;

        if (m_hashMapIndividualsFitness != null)
        {
            size = m_hashMapIndividualsFitness.size();
        }
        return size;
    }

    @Override
    public Iterator<Individual<T>> iterator()
    {
        Iterator<Individual<T>> iterator = null;

        if (m_hashMapIndividualsFitness != null)
        {
            iterator = m_hashMapIndividualsFitness.keySet().iterator();
        }
        return iterator;
    }
}
